package com.circle.interests.biz.core.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.circle.common.core.enums.Switch;
import com.circle.common.core.exception.RRException;
import com.circle.interests.biz.core.PrizeInventoryManageService;
import com.circle.interests.biz.core.protocol.InventoryAllocateCondition;
import com.circle.interests.biz.core.protocol.InventoryConsumeCondition;
import com.circle.interests.biz.core.protocol.InventoryRollbackCondition;
import com.circle.interests.biz.entity.PrizeInfo;
import com.circle.interests.biz.entity.PrizeInventory;
import com.circle.interests.biz.entity.PrizeWinRecord;
import com.circle.interests.biz.enums.InventoryOperateTypeEnum;
import com.circle.interests.biz.enums.PrizeStatusEnum;
import com.circle.interests.biz.service.IPrizeInfoService;
import com.circle.interests.biz.service.IPrizeInventoryLogService;
import com.circle.interests.biz.service.IPrizeInventoryService;
import com.circle.interests.biz.service.IPrizeWinRecordService;
import com.circle.prize.library.api.dto.PrizeInventoryDto;
import com.circle.prize.library.api.enums.InventoryTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author zhou
 * @date 2021/12/8
 */
@Slf4j
@Component
@Transactional
public class PrizeInventoryManageServiceImpl implements PrizeInventoryManageService {

    @Resource
    private IPrizeInfoService prizeInfoService;
    @Resource
    private IPrizeWinRecordService prizeWinRecordService;
    @Resource
    private IPrizeInventoryService prizeInventoryService;
    @Resource
    private IPrizeInventoryLogService prizeInventoryLogService;

    @Override
    public void allocateInventory(InventoryAllocateCondition condition) {
        List<PrizeInventoryDto> prizeInventoryList = condition.getPrizeInventoryList();
        if (CollectionUtil.isEmpty(prizeInventoryList)) {
            return;
        }
        for (PrizeInventoryDto dto : prizeInventoryList) {
            PrizeInfo prizeInfo = prizeInfoService.getByCode(dto.getPrizeCode());
            if (prizeInfo == null) {
                throw new RRException("奖品" + dto.getPrizeCode() + "不存在");
            }
            if (InventoryTypeEnum.LIMITED_NUMBER.getCode().equals(prizeInfo.getInventoryType())
                    && !InventoryTypeEnum.LIMITED_NUMBER.getCode().equals(dto.getType())) {
                throw new RRException("该奖品的库存类型" + InventoryTypeEnum.LIMITED_NUMBER.getInfo()
                        + "不符合分配方式:" + InventoryTypeEnum.getByCode(dto.getType(), InventoryTypeEnum.UNLIMITED).getInfo());
            } else if (InventoryTypeEnum.LIMITED_AMOUNT.getCode().equals(prizeInfo.getInventoryType())
                    && !InventoryTypeEnum.LIMITED_AMOUNT.getCode().equals(dto.getType())) {
                throw new RRException("该奖品的库存类型" + InventoryTypeEnum.LIMITED_AMOUNT.getInfo()
                        + "不符合分配方式:" + InventoryTypeEnum.getByCode(dto.getType(), InventoryTypeEnum.UNLIMITED).getInfo());
            }
            if (prizeInfoService.decrement(prizeInfo, dto.getTotal())) {
                PrizeInventory prizeInventory = prizeInventoryService.allocateInventory(condition.getSceneType(), condition.getSceneId(), prizeInfo.getId(), dto.getType(), dto.getTotal());
                prizeInventoryLogService.saveLog(prizeInventory.getId(), InventoryOperateTypeEnum.ALLOCATION.getCode(), dto.getTotal(), "sys", "");
            }
        }
    }

    @Override
    public boolean consumeInventory(InventoryConsumeCondition condition) {
        Integer sceneType = condition.getSceneType();
        String sceneId = condition.getSceneId();
        Long prizeId = condition.getPrizeId();
        PrizeInventory prizeInventory = prizeInventoryService.getPrizeInventory(sceneType, sceneId, prizeId);
        return modifyRemain(prizeInventory, prizeId, condition.getPrizeCount(), -Math.abs(condition.getPrizePrice()));
    }

    @Override
    public void recycleInventory(InventoryRollbackCondition condition) {
        Long recordId = condition.getRecordId();
        PrizeWinRecord record = prizeWinRecordService.getById(recordId);
        if (record == null) {
            throw new RRException("中奖记录不存在");
        }
        if (Switch.ON.getCode().equals(record.getRecycleFlag())) {
            log.warn("奖品已经回收过：{}", recordId);
            return;
        }
        if (!PrizeStatusEnum.NOT_RECEIVE.getCode().equals(record.getStatus())
                && !PrizeStatusEnum.EXPIRED_OF_NOT_RECEIVE.getCode().equals(record.getStatus())
                && !PrizeStatusEnum.EXPIRED_OF_RECEIVED.getCode().equals(record.getStatus())) {
            throw new RRException("奖品不可回收");
        }
        PrizeWinRecord update = new PrizeWinRecord();
        update.setRecycleFlag(Switch.ON.getCode());
        boolean recycleSuccess = prizeWinRecordService.update(update, Wrappers.lambdaUpdate(PrizeWinRecord.class)
                .eq(PrizeWinRecord::getId, record.getId())
                .eq(PrizeWinRecord::getRecycleFlag, record.getRecycleFlag()));
        if (recycleSuccess) {
            // 恢复活动库存
            PrizeInfo prizeInfo = prizeInfoService.getById(record.getPrizeId());
            prizeInventoryService.modifyInventory(record.getSceneType(), record.getSceneId(), prizeInfo.getCode(), 1);
            Integer sceneType = record.getSceneType();
            String sceneId = record.getSceneId();
            Long prizeId = record.getPrizeId();
            PrizeInventory prizeInventory = prizeInventoryService.getPrizeInventory(sceneType, sceneId, prizeId);
            boolean modifyRemain = modifyRemain(prizeInventory, prizeId, 1, record.getPrizePrice());
            if (!modifyRemain) {
                log.error("修改活动库存余量失败，回滚奖品回收标志,{}", recordId);
                throw new RRException("修改活动库存余量失败");
            }
        }
    }

    private boolean modifyRemain(PrizeInventory prizeInventory, Long prizeId, Integer count, Integer price) {
        if (prizeInventory == null) {
            throw new RRException("未找到该库存");
        }
        Integer number;
        InventoryTypeEnum inventoryType = InventoryTypeEnum.getByCode(prizeInventory.getInventoryType());
        switch (inventoryType) {
            case UNLIMITED:
                log.info("不限量奖品");
                return true;
            case LIMITED_NUMBER:
                number = count;
                break;
            case LIMITED_AMOUNT:
                if (price == null) {
                    throw new RRException("奖品金额不能为空");
                }
                number = count * price;
                break;
            default:
                throw new RRException("不支持的库存类型库存类型:" + prizeInventory.getInventoryType());
        }
        log.info("开始修改活动【{}】的奖品【{}】的库存【{}】,库存总量:{},库存剩余量:{}", prizeInventory.getSceneId(), prizeId, number, prizeInventory.getTotal(), prizeInventory.getRemain());
        // 校验库存
        if (prizeInventory.getRemain() + number < 0 || prizeInventory.getRemain() + number > prizeInventory.getTotal()) {
            return false;
        }
        // todo ABA问题后面引入缓存再优化
        PrizeInventory update = new PrizeInventory();
        update.setRemain(prizeInventory.getRemain() + number);
        return prizeInventoryService.update(update, Wrappers.lambdaUpdate(PrizeInventory.class)
                .eq(PrizeInventory::getId, prizeInventory.getId())
                .eq(PrizeInventory::getRemain, prizeInventory.getRemain()));
    }

}
